package com.yangcangclub.commons.utils;

import org.springframework.util.Assert;

import java.io.PrintWriter;

/**
 * 异常Utility
 *
 */
public final class ExceptionUtils {
	
	private final static String CAUSE_BY = "Cause By";
	
	private ExceptionUtils(){}
	
	public static boolean isCheckedException(Throwable ex) {
		return !(ex instanceof RuntimeException || ex instanceof Error);
	}

	@SuppressWarnings("rawtypes") 
	public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) {
		if (!isCheckedException(ex)) {
			return true;
		}
		if (declaredExceptions != null) {
			int i = 0;
			while (i < declaredExceptions.length) {
				if (declaredExceptions[i].isAssignableFrom(ex.getClass())) {
					return true;
				}
				i++;
			}
		}
		return false;
	}
	
	/**
	 * 得到异常栈信息
	 * @param e
	 * @return
	 */
    public static String toString(Throwable e) {
    	UnsafeStringWriter w = new UnsafeStringWriter();
        PrintWriter p = new PrintWriter(w);
        p.print(e.getClass().getName());
        if (e.getMessage() != null) {
            p.print(": " + e.getMessage());
        }
        p.println();
        try {
            e.printStackTrace(p);
            return w.toString();
        } finally {
            p.close();
        }
    }
    
    public static String toFullString(Throwable e,Throwable cause) {
    	String exception =  toString(e);
    	String causeException =  toString(cause);
    	return exception + CAUSE_BY + causeException;
    }
    
    /**
     * 得到异常栈信息
     * @param msg
     * @param e
     * @return
     */
    public static String toString(String msg, Throwable e) {
    	UnsafeStringWriter w = new UnsafeStringWriter();
        w.write(msg + "\n");
        PrintWriter p = new PrintWriter(w);
        try {
            e.printStackTrace(p);
            return w.toString();
        } finally {
            p.close();
        }
    }
    
    /**
     * 得到底层异常
     * @param e
     * @return
     */
    public static Throwable getRootCauseException(Throwable e) {
    	Assert.notNull(e, "the throwable is not null!");
    	Throwable rootCause = null;
    	while(true) {
    		if(ObjectUtils.isNotNull(rootCause)) {
    			rootCause = rootCause.getCause();
    		} else {
    			rootCause = e.getCause();
    			if(ObjectUtils.isNull(rootCause)) {
    				break;
    			}
    		}
    		if(ObjectUtils.isNull(rootCause.getCause())) {
				break;
			}
    	}
	    return ObjectUtils.isNull(rootCause)?e:rootCause;
    }
}
